package com.suncky.frame.utils;

import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.IntDef;

import com.suncky.frame.AppConfig;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;

/**
 * 日志输出控制类
 */
public class LogUtils {


    @IntDef({LEVEL_NONE, LEVEL_VERBOSE, LEVEL_DEBUG, LEVEL_INFO, LEVEL_WARN, LEVEL_ERROR, LEVEL_ALL})
    @Retention(RetentionPolicy.SOURCE)
    public @interface Level {}

    /**
     * 日志输出级别NONE
     */
    public static final int LEVEL_NONE = 0;
    /**
     * 日志输出级别V
     */
    public static final int LEVEL_VERBOSE = 1;
    /**
     * 日志输出级别D
     */
    public static final int LEVEL_DEBUG = 2;
    /**
     * 日志输出级别I
     */
    public static final int LEVEL_INFO = 3;
    /**
     * 日志输出级别W
     */
    public static final int LEVEL_WARN = 4;
    /**
     * 日志输出级别E
     */
    public static final int LEVEL_ERROR = 5;
    /**
     * 全部日志级别
     */
    public static final int LEVEL_ALL = 6;

    /**
     * 用于记时的变量
     */
    private static long mTimestamp = 0;
    /**
     * 写文件的锁对象
     */
    private static final Object mLogLock = new Object();

    private static final Config config = new Config();

    public static final class Config {
        private String globalTag;
        private @Level
        int level;
        private boolean log2File;
        private String logFilePath;
        private boolean logSwitch = true;//日志开关

        private Config() {
            globalTag= "log_utils";
            level = LEVEL_ALL;
            log2File = false;
            logFilePath = AppConfig.filePath;
        }

        public Config setGlobalTag(String globalTag) {
            this.globalTag = globalTag;
            return this;
        }

        public Config setLevel(int level) {
            this.level = level;
            return this;
        }

        public Config setLog2File(boolean log2File) {
            this.log2File = log2File;
            return this;
        }

        public Config setLogFilePath(String logFilePath) {
            this.logFilePath = logFilePath;
            return this;
        }

        public Config setLogSwitch(boolean logSwitch) {
            this.logSwitch = logSwitch;
            return this;
        }
    }

    /**
     * 设置全局tag
     * @param globalTag
     * @return
     */
    public static Config setGlobalTag(String globalTag) {
        config.setGlobalTag(globalTag);
        return config;
    }

    /**
     * 设置输出的日志级别
     * @param level
     * @return
     */
    public static Config setLogLevel(@Level int level){
        config.setLevel(level);
        return config;
    }
    /**
     * 是否输出到文件(.txt)
     * @param log2File
     * @return
     */
    public static Config setLog2File(boolean log2File) {
        config.setLog2File(log2File);
        return config;
    }
    /**
     * 设置输出日志文件的路径
     * @param logFilePath
     * @return
     */
    public static Config setLogFilePath(String logFilePath) {
        config.setLogFilePath(logFilePath);
        return config;
    }

    /**
     * 日志开关(默认打开)
     * @param logSwitch true-打开 false -关闭
     * @return
     */
    public static Config setLogSwitch(boolean logSwitch) {
        config.setLogSwitch(logSwitch);
        return config;
    }

    /**
     * 以级别为 d 的形式输出LOG
     */
    public static void v(String msg) {
        if (config.level >= LEVEL_VERBOSE) {
            log(LEVEL_VERBOSE, config.globalTag, msg);
        }
    }

    /**
     * 以级别为 d 的形式输出LOG
     */
    public static void d(String msg) {
        if (config.level >= LEVEL_DEBUG) {
            log(LEVEL_DEBUG, config.globalTag, msg);
        }
    }

    /**
     * 以级别为 i 的形式输出LOG
     */
    public static void i(String msg) {
        if (config.level >= LEVEL_INFO) {
            log(LEVEL_INFO, config.globalTag, msg);
        }
    }

    /**
     * 以级别为 w 的形式输出LOG
     */
    public static void w(String msg) {
        if (config.level >= LEVEL_WARN) {
            log(LEVEL_WARN, config.globalTag, msg);
        }
    }

    /**
     * 以级别为 w 的形式输出Throwable
     */
    public static void w(Throwable tr) {
        if (config.level >= LEVEL_WARN) {
            log(LEVEL_WARN, config.globalTag, Log.getStackTraceString(tr));
        }
    }

    /**
     * 以级别为 w 的形式输出LOG信息和Throwable
     */
    public static void w(Throwable tr, String msg) {
        if (config.level >= LEVEL_WARN) {
            log(LEVEL_WARN, config.globalTag, msg + '\n' + Log.getStackTraceString(tr));
        }
    }

    /**
     * 以级别为 e 的形式输出LOG
     */
    public static void e(String msg) {
        if (config.level >= LEVEL_ERROR) {
            log(LEVEL_ERROR, config.globalTag, msg);
        }
    }

    /**
     * 以级别为 e 的形式输出Throwable
     */
    public static void e(Throwable tr) {
        if (config.level >= LEVEL_ERROR) {
            log(LEVEL_ERROR, config.globalTag, Log.getStackTraceString(tr));
        }
    }

    /**
     * 以级别为 e 的形式输出LOG信息和Throwable
     */
    public static void e(Throwable tr,String msg) {
        if (config.level >= LEVEL_ERROR) {
            log(LEVEL_ERROR, config.globalTag, msg + '\n' + Log.getStackTraceString(tr));
        }
    }

    /**
     * 以级别为 d 的形式输出LOG
     */
    public static void v(String tag, String msg) {
        if (config.level >= LEVEL_VERBOSE) {
            log(LEVEL_VERBOSE, tag, msg);
        }
    }

    /**
     * 以级别为 d 的形式输出LOG
     */
    public static void d(String tag, String msg) {
        if (config.level >= LEVEL_DEBUG) {
            log(LEVEL_DEBUG, tag, msg);
        }
    }

    /**
     * 以级别为 i 的形式输出LOG
     */
    public static void i(String tag, String msg) {
        if (config.level >= LEVEL_INFO) {
            log(LEVEL_INFO, tag, msg);
        }
    }

    /**
     * 以级别为 w 的形式输出LOG
     */
    public static void w(String tag, String msg) {
        if (config.level >= LEVEL_WARN) {
            log(LEVEL_WARN, tag, msg);
        }
    }

    /**
     * 以级别为 w 的形式输出Throwable
     */
    public static void w(String tag, Throwable tr) {
        if (config.level >= LEVEL_WARN) {
            log(LEVEL_WARN, tag, Log.getStackTraceString(tr));
        }
    }

    /**
     * 以级别为 w 的形式输出LOG信息和Throwable
     */
    public static void w(String tag, Throwable tr, String msg) {
        if (config.level >= LEVEL_WARN) {
            log(LEVEL_WARN, tag, msg + '\n' + Log.getStackTraceString(tr));
        }
    }

    /**
     * 以级别为 e 的形式输出LOG
     */
    public static void e(String tag, String msg) {
        if (config.level >= LEVEL_ERROR) {
            log(LEVEL_ERROR, tag, msg);
        }
    }

    /**
     * 以级别为 e 的形式输出Throwable
     */
    public static void e(String tag, Throwable tr) {
        if (config.level >= LEVEL_ERROR) {
            log(LEVEL_ERROR, tag, Log.getStackTraceString(tr));
        }
    }

    /**
     * 以级别为 e 的形式输出LOG信息和Throwable
     */
    public static void e(String tag, Throwable tr, String msg) {
        if (config.level >= LEVEL_ERROR && null != msg) {
            log(LEVEL_ERROR, tag, msg + '\n' + Log.getStackTraceString(tr));
        }
    }

    /**
     * 把Log存储到文件中
     * @param log  需要存储的日志
     */
    public static void log2File(String log) {
        String path = config.logFilePath + DateUtils.convertMillisecondsToString(System.currentTimeMillis(), "yyyy-MM-dd")+".log";
        log2File(log, path, true);
    }

	/**
	 * 把Log存储到文件中
	 * @param log  需要存储的日志
	 * @param path 存储路径
	 */
	public static void log2File(String log, String path) {
		log2File(log, path, true);
	}

    public static void log2File(String log, String path, boolean append) {
        if (!config.logSwitch) {
            return;
        }
        synchronized (mLogLock) {
            FileUtil.writeFile("[" + DateUtils.convertMillisecondsToString(System.currentTimeMillis(), "yyyy-MM-dd-HH-mm-ss-SSS")
                    + "]" + log + "\r\n", path, append);
        }
    }

    /**
     * 以级别为 e 的形式输出msg信息,附带时间戳，用于输出一个时间段起始点
     *
     * @param msg 需要输出的msg
     */
    public static void startTime(String msg) {
        mTimestamp = System.currentTimeMillis();
        if (!TextUtils.isEmpty(msg)) {
            e("[Started：" + mTimestamp + "]" + msg);
        }
    }

    /**
     * 以级别为 e 的形式输出msg信息,附带时间戳，用于输出一个时间段结束点
     *  @param msg 需要输出的msg
     */
    public static void endTime(String msg) {
        long currentTime = System.currentTimeMillis();
        long elapsedTime = currentTime - mTimestamp;
        mTimestamp = currentTime;
        e("[End：" + currentTime +" Duration:"+elapsedTime+ "ms]" + msg);
    }

    public static <T> void printList(List<T> list) {
        if (list == null || list.size() < 1) {
            return;
        }
        int size = list.size();
        i("---list begin---");
        for (int i = 0; i < size; i++) {
            i(i + ":" + list.get(i).toString());
        }
        i("---list end---");
    }

    public static <T> void printArray(T[] array) {
        if (array == null || array.length < 1) {
            return;
        }
        int length = array.length;
        i("---array begin---");
        for (int i = 0; i < length; i++) {
            i(i + ":" + array[i].toString());
        }
        i("---array end---");
    }

    private static void log(int level,String tag,String content) {
        if (!config.logSwitch) {
            return;
        }
        //log最大长度为4*1024字节，一个中文字符为2个字节
        int maxLength = 2048 - 2 * tag.length();
        while (content.length() > maxLength) {
            logSection(level,tag, content.substring(0, maxLength));
            content = content.substring(maxLength);
        }
        //输出剩余部分
        logSection(level,tag, content);
        if (config.log2File) {
            log2File(content);
        }
    }

    private static void logSection(int level,String tag,String content) {
        switch (level) {
            case LEVEL_VERBOSE:
                Log.v(tag, content);
                break;
            case LEVEL_DEBUG:
                Log.d(tag, content);
                break;
            case LEVEL_INFO:
                Log.i(tag, content);
                break;
            case LEVEL_WARN:
                Log.w(tag, content);
                break;
            case LEVEL_ERROR:
                Log.e(tag, content);
                break;
            default:
                break;
        }
    }
}
